<?php

namespace App\Shx\Model;

use Storage;
use Illuminate\Support\Str;
use Illuminate\Contracts\Filesystem\Filesystem as FilesystemInterface;
use Illuminate\Contracts\Filesystem\FileNotFoundException;

class BaseFile
{
    const ANCHOR_BREAK = '@';
    const PATH_BREAK = '/';

    //filesystem
    protected $disk;
    protected $disk_name;
    protected $path;
    protected $file;
    protected $file_name;
    protected $anchor;

    protected $proxy_cache;
    protected $proxy_mapping = [
        'mime_type'     => 'mimeType',
        'size'          => 'size',
        'last_modified' => 'lastModified',
        'exists'        => 'exists',
    ];

    public function __construct($uri, $file = null)
    {
        $this->parseUri($uri, !$file);
        
        if($file) {
            $this->file = $file;
        }
    }

    protected function parseUri($uri, $has_file = true) 
    {
        $parse = explode(self::PATH_BREAK, $uri, 2);
        
        if(!isset($parse[0])){
            throw new Exception("Parse URI fail: {$uri}.");
        }
        
        $this->disk_name = $parse[0];
        $this->disk = Storage::disk($parse[0]);
        
        if(isset($parse[1])) {
            $parse = explode(self::PATH_BREAK, $parse[1]);

            if($has_file) {
                $index = count($parse) - 1;
                $info = explode(self::ANCHOR_BREAK, $parse[$index], 2);
                $this->file_name = $info[0];
                $this->anchor = isset($info[1]) ? $info[1] : '';
                unset($parse[$index]);
            }

            $this->path = implode(self::PATH_BREAK, $parse);
        } 
        
        if($this->path) {
            $this->path = self::PATH_BREAK.$this->path.self::PATH_BREAK;
        } else {
            $this->path = self::PATH_BREAK;
        }
        
        return $this;
    }

    public function fileExists()
    {
        return $this->disk->exists($this->fullpath);
    }

    public static function find($uri)
    {
        $model = new static($uri);

        return $model->fileExists() ? $model : null;
    }

    public static function findOrFail($uri)
    {
        if($model = static::find($uri)) {
            return $model;
        }

        throw new FileNotFoundException("File not found at uri: $uri.");
    }

    public static function create($path, $file)
    {
        $model = new static($path, false);
        
        $model->file_name = md5_file($file);

        if($old = static::find($model->uri)) {
            return $old;
        }
        
        return $model->saveFile($file);
    }

    protected function saveFile($file)
    {
        $this->disk->putFileAs($this->path, $file, $this->file_name);

        return $this;
    }

    public function getContent()
    {
        $this->file = $this->disk->get($this->fullpath);

        return $this->file;
    }

    protected function getDataFromProxyModel($key)
    {
        if(empty($this->proxy_cache[$key])) {
            $this->proxy_cache[$key] = $this->disk->{$this->proxy_mapping[$key]}($this->fullpath);
        }
        return $this->proxy_cache[$key];
    }

    //geter 
    public function __get($key)
    {
        if(array_key_exists($key, $this->proxy_mapping)) {
            return $this->getDataFromProxyModel($key);
        }
        
        switch($key){
            case 'uri' :
                return $this->disk_name.$this->path.$this->file_name;
            case 'fullpath' :
                //完整路径
                return $this->path.$this->file_name;
            case 'content' :
                return $this->getContent();
        }

        throw new \ErrorException("Undefinedd property: ".__CLASS__."::$$key");
    }

}